#include "tfp825r6l.h"

u16 temp_reg_id = 0;
u8 temp_buf_id = 0;

static u16 buildComData(u8 *data, u8 com);
static u8 processAskCode(u8 *ask_buf, u8 size);

void TFP_Init(void)
{
	//.. 丢弃指纹模块上电后第一个数据包
	TFTP_RECEVICED_FLAG = 0;
	TFTP_RECEIVED_LEN = 0;
	memset(TFTP_BUFFER,0,U3_RXBUF_SIZE);
	HAL_UART_Receive_DMA(&USE_USART, TFTP_BUFFER, U3_RXBUF_SIZE);
}
/*	数据包格式
头部 	地址 		包类型 		包长度 		内容 								校验和
2 		字节 		4 字节 		1 字节 		2 字节 (N-2) 字节 	2 字节

名称 			标记 				大小 	描述
头 				START 			2 		0xEF01
地址 			ADDR 				4 		0xFFFFFFFF, module address 
包类型 		PID 				1 		0x01 命令包
0x02 			数据包
0x07 			响应包
0x08 			最后数据包
包长度 		LENGTH 			2 		内容与校验和占用的空间总字节长度
类型 			PAYLOAD 		-
校验和 		SUM 				2 		从 PID 到内容的每个字节的累积和
*/
//发送命令
#pragma pack(1)
typedef struct
{
	u16 start_seg;
	u32 addr_seg;
	u8 pid_seg;
	u16 length_seg;
	u8 *com_data;
	u16 sum_seg;
} TFP_COM_STRU;

//返回0：执行命令成功		返回1：执行命令出错
static u8 processAskCode(u8 *ask_buf, u8 size)
{

	printf("接受到的返回数据:");
	for (int i = 0; i < size; i++)
	{
		printf("0x%02x ", ask_buf[i]);
	}
	printf("\r\n");
	switch (ask_buf[9])
	{
	case RET_OK:
		printf("succeed code:%x:RET_OK 命令执行成功																\r\n", RET_OK);
		return RET_OK;
	case RET_InvalidPacket:
		printf("err code:%x,note:RET_InvalidPacket 无效数据包											\r\n", RET_InvalidPacket);
		return RET_InvalidPacket;
	case RET_NoFinger:
		printf("err code:%x,note:RET_NoFinger 传感器未检测到手指										\r\n", RET_NoFinger);
		return RET_NoFinger;
	case RET_StoreImageFail:
		printf("err code:%x,note:RET_StoreImageFail 将图像存入 ImageBuffer 失败		\r\n", RET_StoreImageFail);
		return RET_StoreImageFail;
	case RET_TooLowQuality:
		printf("err code:%x,note:RET_TooLowQuality 图像质量太差而无法提取特征			\r\n", RET_TooLowQuality);
		return RET_TooLowQuality;
	case RET_TooFewPoint:
		printf("err code:%x,note:RET_TooFewPoint 特征点太少而无法提取特征					\r\n", RET_TooFewPoint);
		return RET_TooFewPoint;
	case RET_NotMatched:
		printf("err code:%x,note:RET_NotMatched 指纹模板匹配不一致									\r\n", RET_NotMatched);
		return RET_NotMatched;
	case RET_NotIdentified:
		printf("err code:%x,note:RET_NotIdentified 没有找到匹配的指纹							\r\n", RET_NotIdentified);
		return RET_NotIdentified;
	case RET_MergeFail:
		printf("err code:%x,note:RET_MergeFail 合并特征失败												\r\n", RET_MergeFail);
		return RET_MergeFail;
	case RET_InvalidTempID:
		printf("err code:%x,note:RET_InvalidTempID 模板 ID 不合法									\r\n", RET_InvalidTempID);
		return RET_InvalidTempID;
	case RET_ReadTempFail:
		printf("err code:%x,note:RET_ReadTempFail 从数据库中读出模板失败						\r\n", RET_ReadTempFail);
		return RET_ReadTempFail;
	case RET_UpTempFail:
		printf("err code:%x,note:RET_UpTempFail 上传模板失败												\r\n", RET_UpTempFail);
		return RET_UpTempFail;
	case RET_ModBusyErr:
		printf("err code:%x,note:RET_ModBusyErr 此时模组不能接收数据包							\r\n", RET_ModBusyErr);
		return RET_ModBusyErr;
	case RET_UpImgFail:
		printf("err code:%x,note:RET_UpImgFail 上传图像失败												\r\n", RET_UpImgFail);
		return RET_UpImgFail;
	case RET_RemoveTempFail:
		printf("err code:%x,note:RET_RemoveTempFail 从数据库中删除模板失败					\r\n", RET_RemoveTempFail);
		return RET_RemoveTempFail;
	case RET_RemoveAllFail:
		printf("err code:%x,note:RET_RemoveAllFail 从数据库中删除所有模板失败			\r\n", RET_RemoveAllFail);
		return RET_RemoveAllFail;
	case RET_InvalidPwd:
		printf("err code:%x,note:RET_InvalidPwd 无效密码														\r\n", RET_InvalidPwd);
		return RET_InvalidPwd;
	case RET_InvalidImg:
		printf("err code:%x,note:RET_InvalidImg ImageBuffer 中没有有效的图像数据 	\r\n", RET_InvalidImg);
		return RET_InvalidImg;
	case RET_InvalidMAddr:
		printf("err code:%x,note:RET_InvalidMAddr 非法的模组地址										\r\n", RET_InvalidMAddr);
		return RET_InvalidMAddr;
	case RET_NeedVfyPwd:
		printf("err code:%x,note:RET_NeedVfyPwd 需要验证密码												\r\n", RET_NeedVfyPwd);
		return RET_NeedVfyPwd;
	default:
		printf("exec CMD failed! \r\n");
		return 0xff;
	}
}

/*
@param:	构建后的数据保存地址
@com:		命令
@return: 返回保存地址的有效字节个数
*/
static u16 buildComData(u8 *buf, u8 com)
{
	//	u8 * buf;
	u16 data_size, com_data_size;
	u8 *com_data;

	TFP_COM_STRU com_stru;
	//	u8 com_size = sizeof(com_stru);

	if (com == TFTP_GetImg) //获取图像（包含手指检测）
	{
		data_size = 12, com_data_size = 1;
   		com_data = malloc(com_data_size);
		*com_data = 0x01;
		com_stru.com_data = com_data;
	}
	else if (com == TFTP_Img2Tz) //特征提取
	{
		data_size = 13, com_data_size = 2;
		com_data = malloc(com_data_size);
		com_data[0] = TFTP_Img2Tz; //指令码
		com_data[1] = temp_buf_id; //特征缓冲区编号
		com_stru.com_data = com_data;
	}
	else if (com == TFTP_RegModel) //将 2 个特征合并成 1 个模板
	{
		data_size = 12, com_data_size = 1;
		com_data = malloc(com_data_size);
		com_data[0] = TFTP_RegModel;
		com_stru.com_data = com_data;
	}
	else if (com == TFTP_StoreModel)
	{
		data_size = 15, com_data_size = 4;
		com_data = malloc(com_data_size);
		com_data[0] = TFTP_StoreModel;
		com_data[1] = 0x01;
		com_data[2] = temp_reg_id >> 8;
		com_data[3] = temp_reg_id;
		com_stru.com_data = com_data;
	}
	else if (com == TFTP_Search)
	{
		data_size = 17, com_data_size = 6;
		com_data = malloc(com_data_size);
		com_data[0] = TFTP_Search;
		com_data[1] = 0x01;
		com_data[2] = SEARCH_START_ID >> 8;
		com_data[3] = SEARCH_START_ID;
		com_data[4] = SEARCH_COUNT >> 8;
		com_data[5] = SEARCH_COUNT;
		com_stru.com_data = com_data;
	}
	else if (com == TFTP_Empty)
	{
		data_size = 12, com_data_size = 1;
		com_data = malloc(com_data_size);
		com_data[0] = TFTP_Empty;
		com_data[1] = 0x01;
		com_stru.com_data = com_data;
	}else if (com == TFTP_AutoIdentify)
	{
		//ef 01 ff ff ff ff 01 00 08 b8 78 00 20 a1 01 02 40
		data_size = 17,com_data_size = 6;
		com_data = malloc(com_data_size);
		com_data[0] = TFTP_AutoIdentify;
		com_data[1] = 0x03;	//Security level
		com_data[2] = 0xff;	//ID
		com_data[3] = 0xff;	
		com_data[4] = 0x00;	//Control Para
		com_data[5] = 0x04;
		com_stru.com_data = com_data;
	}

	com_stru.start_seg = 0xef01;
	com_stru.addr_seg = 0xffffffff;
	com_stru.pid_seg = 0x01;
	com_stru.length_seg = com_data_size + 2;
	//	u8 temp = 0x01;
	//	com_stru.com_data = &temp;
	com_stru.sum_seg = com_stru.pid_seg + com_stru.length_seg;
	for (int i = 0; i < com_data_size; i++)
	{
		com_stru.sum_seg += com_data[i];
	}

	com_stru.start_seg = CH_SwitchU16(com_stru.start_seg);
	//	com_stru.addr_seg = CH_SwitchU32(com_stru.addr_seg);
	com_stru.length_seg = CH_SwitchU16(com_stru.length_seg);
	com_stru.sum_seg = CH_SwitchU16(com_stru.sum_seg);

	//	buf = malloc(data_size);
	//.. 构建 buf 数据
	u8 *temp = buf;
	memcpy(buf, &com_stru.start_seg, sizeof(com_stru.start_seg));
	buf += sizeof(com_stru.start_seg);
	memcpy(buf, &com_stru.addr_seg, sizeof(com_stru.addr_seg));
	buf += sizeof(com_stru.addr_seg);
	memcpy(buf, &com_stru.pid_seg, sizeof(com_stru.pid_seg));
	buf += sizeof(com_stru.pid_seg);
	memcpy(buf, &com_stru.length_seg, sizeof(com_stru.length_seg));
	buf += sizeof(com_stru.length_seg);
	memcpy(buf, com_stru.com_data, com_data_size);
	//{for} build com_data
	for (int i = 0; i < com_data_size; i++)
	{
		buf[i + 9] = com_stru.com_data[i];
	}
	buf += com_data_size;
	memcpy(buf, &com_stru.sum_seg, sizeof(com_stru.sum_seg));
	buf = temp; //@ 从新定位到首地址
	free(com_data);

	return data_size;
}
//清除所有注册了的指纹
u8 TFP_DelateAllFingerPrint(void)
{
	u8 ret = 0;
	ret = TFP_ExecCOM(TFTP_Empty);
	return ret;
}

//发送给 Img2Tz 命令
u8 TFP_SendImg2TzCOM(u8 buf_id)
{
	u8 ret = 0;
	temp_buf_id = buf_id;
	ret = TFP_ExecCOM(TFTP_Img2Tz);
	return ret;
}

//发送 StoreModel 命令
u8 TFP_SendStoreModelCOM(u16 reg_id)
{
	u8 ret = 0;
	temp_reg_id = reg_id;
	ret = TFP_ExecCOM(TFTP_StoreModel);
	return ret;
}

u8 TFP_SearchFingerPrint(void)
{
	u8 ret = TFP_ExecCOM(TFTP_Search);
	return ret;
}

//执行命令
u8 TFP_ExecCOM(u8 com)
{
	u8 ret = 0;
	u8 com_buf[100];
	memset(com_buf, 0, sizeof(com_buf));
	u16 com_datasize = buildComData(com_buf, com);
	u8 receive_size = 12;
	u8 receive_data[receive_size];

	printf("发送命令：");
	for (int i = 0; i < com_datasize; i++)
	{
		printf("%02x ", com_buf[i]);
	}
	printf("\r\n");
	TFP_SendDataBuf(com_buf, com_datasize);

	while (!u3Receiver.recevicedFlag)
	{
		DELAY(500);
	};
	
	u3Receiver.recevicedFlag = 0;
	u8 is_ok = HAL_UART_Receive_DMA(&USE_USART, u3Receiver.buffer, U3_RXBUF_SIZE);
	memcpy(receive_data, u3Receiver.buffer, u3Receiver.receivedLen);

//	TFP_Delay(); //@ 避免发送命令太过频繁，导致调试信息输出太乱
	if (is_ok == HAL_OK)
	{
		ret = processAskCode(receive_data, receive_size);
	}
	else
	{
		printf("获取返命令回数据失败，接受缓冲区内容是:");
		for (int i = 0; i < receive_size; i++)
		{
			printf("%02x ", receive_data[i]);
		}
		printf("\r\n");
		return 0xff;
	}
	return ret;
}

u8 TFP_SendCommonCOM(u8 com)
{
	u8 ret = 0;
	ret = TFP_ExecCOM(com);
	return ret;
}

HAL_StatusTypeDef TFP_SendDataBuf(u8 *buf, u16 size)
{
	return HAL_UART_Transmit(&USE_USART, buf, size, 0xffff);
}

